#include <sys/types.h>         
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <linux/serial.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <unistd.h>


#include <termios.h>

void Test_err(int flg)
{
    if(flg<0)
    {
        perror(strerror(errno));
        exit(1);
    }
}

int main(int argc, char** argv)
{
    printf("usage : %s ?\n",argv[0]);
    


    short listenPort=8888; 
    unsigned char uart_port[100]={"/dev/ttyS2"};
    int bps=0;
    unsigned int   baudRate= B9600;

    int  opt;
    while ((opt=getopt(argc,argv,"p:s:b:?")) != -1)
    {
        switch (opt)
        {
        case 'p':
            listenPort = atoi(optarg);
            break;
        case 's':
            memset(uart_port,0,sizeof(uart_port));
            strncpy(uart_port,optarg,99);
            break;
        case 'b':
            bps = atoi(optarg);
            break;
        default: /* '?' */
                   fprintf(stderr, "Usage: %s [-p port -s serial port  -b baund]  \n",
                           argv[0]);
                   exit(EXIT_FAILURE);
        }
    }

    switch(bps)
    {
    case 4800:
        baudRate=B4800;
        break;
    case 19200:
        baudRate=B19200;
        break;
    case 38400:
        baudRate=B38400;
        break;
    case 57600:
        baudRate=B57600;
        break;
    case 115200:
        baudRate=B115200;
        break;
    default:
        baudRate=B9600;
        bps=9600;
        break;
    }




    printf("tcp-server...enter\n");
    printf("set uartport is %d\n",bps);
    printf("set uartspeed is %s\n",uart_port);
    printf("set tcpport is %d\n",listenPort);

    


// uart--------------------------------------------------------
    int uart_fd=open(uart_port, O_RDWR | O_NOCTTY | O_NDELAY);

    struct termios newtio;
    memset(&newtio,0, sizeof( newtio ));
    newtio.c_cflag=0;
    newtio.c_iflag=0;
    newtio.c_cflag  |=  CLOCAL | CREAD; 
    newtio.c_cflag &= ~CSIZE; 
    newtio.c_cflag |= CS8;
    newtio.c_cflag &= ~PARENB;
    newtio.c_cflag &=  ~CSTOPB; 
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN]  = 0;
    cfsetispeed(&newtio, baudRate);
    cfsetispeed(&newtio, baudRate);
    tcflush(uart_fd,TCIFLUSH);

    if((tcsetattr(uart_fd,TCSANOW,&newtio))!=0)
    {
        perror("uart open error\n");
        return -1;
    }

    // int portfd;
    // #if (__GNUC__ == 4 && __GNUC_MINOR__ == 3)
	// struct my_serial_rs485 rs485conf;
	// struct my_serial_rs485 rs485conf_bak;
    // #else
    // 	struct serial_rs485 rs485conf;
    // 	struct serial_rs485 rs485conf_bak;
    // #endif
    

    // portfd=uart_fd;
    // /* Driver-specific ioctls: ...\linux-3.10.x\include\uapi\asm-generic\ioctls.h */
    // #define TIOCGRS485      0x542E
    // #define TIOCSRS485      0x542F
    // if (ioctl (portfd, TIOCGRS485, &rs485conf) < 0) 
	// {
	// 	/* Error handling.*/ 
	// 	// Log::Inf("ioctl TIOCGRS485 error.\n");
    //     printf( "[ERR] ioctl TIOCGRS485 error.\n");
	// }
	// /* Enable RS485 mode: */
	// rs485conf.flags |= SER_RS485_ENABLED;

	// /* Set logical level for RTS pin equal to 1 when sending: */
	// rs485conf.flags |= SER_RS485_RTS_ON_SEND;
	// //rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;

	// /* set logical level for RTS pin equal to 0 after sending: */ 
	// rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
	// //rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);

	// /* Set rts delay after send, if needed: */
	// rs485conf.delay_rts_after_send = 0x80;

	// if (ioctl (portfd, TIOCSRS485, &rs485conf) < 0)
	// {
	// 	/* Error handling.*/ 
	// 	printf("ioctl TIOCSRS485 error.\n");
        
	// }

	// if (ioctl (portfd, TIOCGRS485, &rs485conf_bak) < 0)
	// {
	// 	/* Error handling.*/ 
	// 	printf("ioctl TIOCGRS485 error.\n");
    // }
    /*----------------------------------------------------*/
    unsigned char test_msg[]="this is send by uart\n";
    int uart_sent_cnt = write(uart_fd, test_msg, sizeof(test_msg));



// tcp--------------------------------------------------------


    int listen_fd=-1;
    int accept_fd=-1;
    int flags;
    int max_listen_num=10;
    unsigned char r_buf[255];
    int n;

    struct sockaddr_in server_addr;
    struct sockaddr_in  clinet_addr;


    


    listen_fd=socket(AF_INET, SOCK_STREAM, 0);
    Test_err(listen_fd);

    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family      = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port        = htons(listenPort);

    int i = 1;/* 允许重复使用本地地址与套接字进行绑定 */
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));

    flags=bind(listen_fd, (struct sockaddr *)&server_addr,sizeof(struct sockaddr));
    Test_err(flags);

    flags= listen(listen_fd, max_listen_num);
    Test_err(flags);

    int clinet_addr_len=sizeof(clinet_addr);
__ACCEPT_AGAIN__:    
    accept_fd= accept(listen_fd, (struct sockaddr *)&clinet_addr, &clinet_addr_len);
    // show clinet message
    printf("accept_fd is %d \n",accept_fd);
    printf("port=%d\n",ntohs(clinet_addr.sin_port));
    unsigned char strbuf[20];
    inet_ntop(AF_INET,&clinet_addr.sin_addr,strbuf,sizeof(strbuf));
    printf("ip=%s\n",strbuf);
    memset(r_buf , 0, sizeof(r_buf));
 


    int maxfd; 
    fd_set rset, allset;
    struct timeval tv;
    FD_ZERO(&allset);
    FD_SET(uart_fd, &allset);
    FD_SET(accept_fd, &allset);
    memset(&tv, 0, sizeof(tv));
    tv.tv_usec = 1000 * 1000;


    int len=0;
    while (accept_fd)
    {
        rset=allset;
        maxfd=(accept_fd>uart_fd?accept_fd:uart_fd);
 
        flags=select(maxfd + 1, &rset, NULL, NULL, &tv);
        Test_err(flags);

        // get from tcp>>>>>uart
        if (FD_ISSET(accept_fd, &rset))
        {
            n = recv(accept_fd, r_buf, 100, 0);
            Test_err(n);
            if(n)
            {
                //write(0,r_buf,n);
                printf("Get from tcp %d\n",n);
                write(uart_fd,r_buf,n);
            }
            else
            {
                printf("socket is disconnect\n");
                goto __ACCEPT_AGAIN__;
            }
        }
        // get from uart>>>>tcp
        else if (FD_ISSET(uart_fd, &rset))
        {
            usleep(100000);//100ms  这里等待接受多一点的数据
            int ret = read(uart_fd, (char*)r_buf,sizeof(r_buf));
            if (ret < 0)
            {
                if ((errno == EAGAIN) ||
                    (errno == EWOULDBLOCK) ||
                    (errno == EINTR))
                {
                    printf("Serial,read timeout error:%s. ignore ti!!!", strerror(errno));
                    ret = 0;
                }
            }
            else
            {
                printf("Get from uart %d\n",ret);
                send(accept_fd, r_buf, ret, 0);
            }
        }
    }
    printf("tcp-server...exit\n");
    return 0;
}